package edu.bw.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@Component
@SuppressWarnings("unchecked")
public class TransactionProxy {
    @Autowired
    TransactionManager transactionManager;
    @Autowired
    ApplicationContext applicationContext;
    public Object  getProxy(Class cls){
        if(cls.getInterfaces().length!=0){
        return Proxy.newProxyInstance(
                cls.getClassLoader(),
                cls.getInterfaces(),
                (proxy, method, args) -> {
                    return invokeWithTransaction(cls, method, args);
                }
                );}
        else {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(cls);
            enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
                return invokeWithTransaction(cls, method, objects);
            });
            return enhancer.create();
        }
    }

    private Object invokeWithTransaction(Class cls, Method method, Object[] objects) throws IllegalAccessException, InvocationTargetException {
        Object ret = null;
        if (method.getName().startsWith("find")) {
            ret = method.invoke(applicationContext.getBean(cls), objects);
        } else {
            transactionManager.beginTransaction();
            try {
                ret = method.invoke(applicationContext.getBean(cls), objects);
                transactionManager.commit();
            } catch (Exception e) {
                transactionManager.rollback();
                throw new RuntimeException(e);
            } finally {
                transactionManager.close();
            }
        }
        return ret;
    }
}

